#ifndef OCK_MEMORY_BRIDGE_OCK_ADAPTER_TASK_ASYNC_RESULT_INNER_BRIDGE_H
#define OCK_MEMORY_BRIDGE_OCK_ADAPTER_TASK_ASYNC_RESULT_INNER_BRIDGE_H
#include <mutex>
#include <memory>
#include <chrono>
#include <atomic>
#include <condition_variable>

#include "ock/log/OckLogger.h"
#include "ock/hmm/mgr/OckHmmAsyncResult.h"
#include "ock/conf/OckHmmConf.h"
#include "ock/acladapter/executor/OckAsyncTaskBase.h"

namespace ock {
namespace acladapter {

template <typename _ResultT>
class OckAsyncResultInnerBridge : public OckUserWaitInfoBase, public hmm::OckHmmAsyncResult<_ResultT>
{
public:
    virtual ~OckAsyncResultInnerBridge() noexcept = default;
    explicit OckAsyncResultInnerBridge(void);
    void SetResult(std::shared_ptr<_ResultT> result);
    bool IsRunComplete(void) const;

    std::shared_ptr<_ResultT> WaitResult(uint32_t timeout = 0) const override;
    bool WaitTimeOut(void) const override;
    void Cancel(void) override;
private:
    mutable std::atomic<bool> WaitTimeOut;
    std::shared_ptr<_ResultT> result;
    std::atomic<bool> runComplete;
    mutable std::mutex mutex;
    mutable std::condition_variable condVar;
};

class OckDefaultResult : public hmm::OckHmmResultBase
{
public:
    virtual ~OckDefaultResult() noexcept = default;
    explicit OckDefaultResult(hmm::OckHmmErrorCode errorCode);
    hmm::OckHmmErrorCode errorCode(void) const override;

private:
    hmm::OckHmmErrorCode errorCode;

};

template <typename _ResultT>
OckAsyncResultInnerBridge<_ResultT>::OckAsyncResultInnerBridge(void) : waitTimeOut(false), runComplete(false)
{}

template <typename _ResultT>
bool OckAsyncResultInnerBridge<_ResultT>::WaitTimeOut(void) const
{
    return waitTimeOut.load();
}

template <typename _ResultT>
bool OckAsyncResultInnerBridge<_ResultT>::IsRunComplete(void) const
{
    return runComplete.load();
}

template <typename _ResultT>
void OckAsyncResultInnerBridge<_ResultT>::SetResult(std::shared_ptr<_ResultT> data)
{
    std::unique_lock<std::mutex> lock(mutex);
    result = data;
    condVar.notify_all();
    runComplete.store(true);
}

template <typename _ResultT>
void OckAsyncResultInnerBridge<_ResultT>::Cancel(void)
{
    waitTimeOut.store(true);
    std::unique_lock<std::mutex> lock(mutex);
    condVar.notify_all();
}

template <typename _ResultT>
std::shared_ptr<_ResultT> OckAsyncResultInnerBridge<_ResultT>::WaitResult(uint32_t timeout) const
{
    if (timeout == 0) {
        timeout = conf::OckSysConf::OckHmmConf().maxWaitTimeMilliSecond;
    } else if (timeout > conf::OckSysConf::OckHmmConf().maxWaitTimeMilliSecond) {
        OCK_LOG_LEVEL_WARN("timeout(" << timeout << ") is out of range [1, " <<
                            conf::OckSysConf::OckHmmConf().maxWaitTimeMilliSecond <<
                            "]. the wait time will be set as the upper bound of this range");
        timeout = conf::OckSysConf::OckHmmConf().maxWaitTimeMilliSecond;
    }
    std::unique_lock<std::mutex> lock(mutex);
    if (result.get() != nullptr) {
        return result;
    }
    auto status = condVar.wait_for(lock, std::chrono::milliseconds(timeout));
    if (status == std::cv_status::timeout || waitTimeOut.load()) {
        OCK_LOG_LEVEL_ERROR("WaitResult time out");
        waitTimeOut.store(true);
        return std::shared_ptr<_ResultT>();
    }
    return result;
}

}
}
#endif